//
//  YHPhotosManager.swift
//  FuweiCloud
//
//  Created by michael on 2024/10/11.
//

import Foundation
import Photos
import UIKit

public typealias YHPhotoLibraryResultBlock = (Bool) -> Void

public enum YHPhotosManager {
  public static let albumName: String = Bundle.main.infoDictionary?["CFBundleName"] as? String ?? ""
    
  public static func checkPhotoLibraryPermission(completion: @escaping YHPhotoLibraryResultBlock) {
    let status: PHAuthorizationStatus
        
    if #available(iOS 14.0, *) {
      status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
    } else {
      status = PHPhotoLibrary.authorizationStatus()
    }
        
    switch status {
    case .authorized:
      completion(true)
    case .notDetermined:
      PHPhotoLibrary.requestAuthorization { status in
        AsyncOnMain {
          completion(status == .authorized)
        }
      }
    case .denied:
      showPermissionAlert(message: "The system album is not authorized. Please go to the system settings to turn on the authorization switch".local)
      completion(false)
    case .limited:
      if #available(iOS 14.0, *) {
        showPermissionAlert(message: "Allow \(albumName) to access your all photos".local)
      }
      completion(false)
    case .restricted:
      YHAlertPopView.pop(properties: [
        .header: "The system album function is restricted and cannot be used".local,
        .leftButton: "Got It".local
      ])
      completion(false)
    @unknown default:
      completion(false)
    }
  }
    
  public static func saveToPhotoLibrary(url: URL, completion: YHPhotoLibraryResultBlock?) {
    checkPhotoLibraryPermission { success in
      if success {
        saveMediaCheckAlbum(url: url, resultBlock: completion)
      } else {
        completion?(false)
      }
    }
  }
}

// MARK: - Private Methods

private extension YHPhotosManager {
  static func showPermissionAlert(message: String) {
    YHAlertPopView.pop(properties: [
      .header: message,
      .rightButton: "Setting".local
    ]) { userInfo in
      guard userInfo != nil else { return }
      YHAppSettingURLHelper.gotoURL(.appSetting)
    }
  }
    
  static func existAlbum() -> PHAssetCollection? {
    var collection: PHAssetCollection?
    let results = PHCollection.fetchTopLevelUserCollections(with: nil)
    results.enumerateObjects { c, _, stop in
      if let c = c as? PHAssetCollection,
         c.localizedTitle == albumName
      {
        collection = c
        stop.pointee = true
      }
    }
    return collection
  }
    
  static func createAlbum(resultBlock: @escaping (PHAssetCollection?) -> Void) {
    PHPhotoLibrary.shared().performChanges({
      PHAssetCollectionChangeRequest.creationRequestForAssetCollection(withTitle: albumName)
    }) { success, _ in
      AsyncOnMain { resultBlock(success ? existAlbum() : nil) }
    }
  }
    
  static func isImage(for url: URL) -> Bool {
    let imageTypes = ["jpg", "png", "tiff", "bmp", "ico", "gif", "heic"]
    return imageTypes.contains(url.pathExtension.lowercased())
  }
    
  static func saveMediaCheckAlbum(url: URL, resultBlock: YHPhotoLibraryResultBlock?) {
    if let assetCollection = existAlbum() {
      saveMedia(assetCollection, url: url, resultBlock: resultBlock)
    } else {
      createAlbum { assetCollection in
        if let assetCollection {
          saveMedia(assetCollection, url: url, resultBlock: resultBlock)
        } else {
          resultBlock?(false)
        }
      }
    }
  }
    
  static func saveMedia(_ assetCollection: PHAssetCollection, url: URL, resultBlock: YHPhotoLibraryResultBlock?) {
    PHPhotoLibrary.shared().performChanges({
      let assetChangeRequest: PHAssetChangeRequest
      if isImage(for: url) {
        assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: url)!
      } else {
        assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url)!
      }
            
      let collectionChangeRequest = PHAssetCollectionChangeRequest(for: assetCollection)
      let assetPlaceholder = assetChangeRequest.placeholderForCreatedAsset
      collectionChangeRequest?.addAssets([assetPlaceholder] as NSFastEnumeration)
    }) { success, error in
      if let error {
        print("save media error:\(error.localizedDescription)")
      }
      AsyncOnMain { resultBlock?(success) }
    }
  }
}
